package com.winit.deploy.factory;

import com.winit.common.base.beans.LoginUser;
import com.winit.common.util.DateUtil;
import com.winit.common.util.LogUtil;
import com.winit.core.server.Server;
import com.winit.core.task.ChainBaseTask;
import com.winit.core.task.Task;
import com.winit.core.task.TaskNode;
import com.winit.deploy.bean.*;
import com.winit.deploy.server.*;
import com.winit.deploy.task.androidTask.AndroidBakTask;
import com.winit.deploy.task.androidTask.AndroidInstallTask;
import com.winit.deploy.task.androidTask.AndroidPrepareTask;
import com.winit.deploy.task.androidTask.AndroidRollBackTask;
import com.winit.deploy.task.phpTask.*;
import com.winit.deploy.task.springBootTask.*;
import com.winit.deploy.task.tomcatTask.*;
import com.winit.project.core.bean.PackageTypeEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by wangjian on 16/8/15.
 */
public class DeployTaskFactory {

    private static final Logger logger = LoggerFactory.getLogger(DeployTaskFactory.class);

    /**
     * 创建发布task
     *
     * @param step
     * @param taskId
     * @param server
     * @param isUserJumpServer
     * @param winitJumpServer
     * @param winitInfo
     * @param needPrepare
     * @return
     */
    public ChainBaseTask createChainBaseTask(PackageTypeEnum typeEnum, DeployStepEnum step, String taskId, Server server, boolean isUserJumpServer
            , WinitJumpServer winitJumpServer, WinitInfo winitInfo, boolean needPrepare, LoginUser userInfo) throws Exception {
        return createChainBaseTask(typeEnum, step, taskId, server, isUserJumpServer, winitJumpServer, winitInfo, createDefaultTaskHandler(), needPrepare, userInfo, true);
    }

    public ChainBaseTask createChainBaseTask(PackageTypeEnum typeEnum, DeployStepEnum step, String taskId, Server server, boolean isUserJumpServer
            , WinitJumpServer jumpServer, WinitInfo winitInfo, ChainBaseTask.TaskHandler handler, boolean needPrepare, LoginUser userInfo, boolean needFailConfirm) throws Exception {
        return createChainBaseTask(typeEnum, step, taskId, server, isUserJumpServer, jumpServer, winitInfo, handler, needPrepare, userInfo, needFailConfirm, false);
    }

    public ChainBaseTask createChainBaseTask(PackageTypeEnum typeEnum, DeployStepEnum step, String taskId, Server server, boolean isUserJumpServer
            , WinitJumpServer jumpServer, WinitInfo winitInfo, ChainBaseTask.TaskHandler handler, boolean needPrepare, LoginUser userInfo, boolean needFailConfirm, boolean isCleanRedis) throws Exception {
        List<TaskNode> taskNodeList = new ArrayList<>();
        switch (step) {
            case ALL:
                if (needPrepare) {
                    taskNodeList.add(getTaskNode(typeEnum, DeployStepEnum.PREPARE, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm));
                }
                switch (typeEnum) {
                    case MAVEN_WAR:
                        taskNodeList.add(getTaskNode(typeEnum, DeployStepEnum.STOP, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm));
                        taskNodeList.add(getTaskNode(typeEnum, DeployStepEnum.BAK, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm));
                        taskNodeList.add(getTaskNode(typeEnum, DeployStepEnum.INSTALL, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm));
                        taskNodeList.add(getTaskNode(typeEnum, DeployStepEnum.START, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm, isCleanRedis));
//                        taskNodeList.add(getTaskNode(typeEnum, DeployStepEnum.VERIFY, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm));
                        break;
                    case PHP:
                    case SPRING_BOOT_JAR:
                        taskNodeList.add(getTaskNode(typeEnum, DeployStepEnum.STOP, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm));
                        taskNodeList.add(getTaskNode(typeEnum, DeployStepEnum.BAK, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm));
                        taskNodeList.add(getTaskNode(typeEnum, DeployStepEnum.INSTALL, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm));
                        taskNodeList.add(getTaskNode(typeEnum, DeployStepEnum.START, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm));
                        break;
                    case ANT_ANDROID:
                        taskNodeList.add(getTaskNode(typeEnum, DeployStepEnum.BAK, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm));
                        taskNodeList.add(getTaskNode(typeEnum, DeployStepEnum.INSTALL, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm));
                        break;
                    default:
                        break;
                }
                break;
            case PREPARE:
            case STOP:
            case BAK:
            case INSTALL:
            case START:
            case VERIFY:
                taskNodeList.add(getTaskNode(typeEnum, step, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm));
                break;
            case ROLLBACK:
                switch (typeEnum) {
                    case MAVEN_WAR:
                        taskNodeList.add(getTaskNode(typeEnum, DeployStepEnum.STOP, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm));
                        taskNodeList.add(getTaskNode(typeEnum, DeployStepEnum.ROLLBACK, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm));
                        taskNodeList.add(getTaskNode(typeEnum, DeployStepEnum.START, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm, isCleanRedis));
                        break;
                    case PHP:
                    case SPRING_BOOT_JAR:
                        taskNodeList.add(getTaskNode(typeEnum, DeployStepEnum.STOP, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm));
                        taskNodeList.add(getTaskNode(typeEnum, DeployStepEnum.ROLLBACK, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm));
                        taskNodeList.add(getTaskNode(typeEnum, DeployStepEnum.START, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm));
                        break;
                    case ANT_ANDROID:
                        taskNodeList.add(getTaskNode(typeEnum, DeployStepEnum.ROLLBACK, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm));
                        break;
                    default:
                        break;
                }
                break;
            case RESTART:
                taskNodeList.add(getTaskNode(typeEnum, DeployStepEnum.STOP, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm));
                taskNodeList.add(getTaskNode(typeEnum, DeployStepEnum.START, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm, isCleanRedis));
            default:
                logger.error("生成发布用ChainBaseTask,参数错误.step=" + step.getStep());
                throw new Exception("生成发布用ChainBaseTask,参数错误.step=" + step.getStep());
        }
        LogUtil.operateLog(userInfo, winitInfo.getProjectName(), winitInfo.getEditionNum(), taskId, step.getOperateType());
        ChainBaseTask chainBaseTask = new ChainBaseTask(taskId, 3600, taskNodeList, handler);
        chainBaseTask.setServer(server);
        return chainBaseTask;
    }

    /**
     * 获取tasknode
     *
     * @param step             发布步骤
     * @param taskId           任务id
     * @param server
     * @param isUserJumpServer 是否使用跳板机
     * @param jumpServer
     * @param winitInfo
     * @return
     */
    private TaskNode getTaskNode(PackageTypeEnum typeEnum, DeployStepEnum step, String taskId, Server server, boolean isUserJumpServer
            , WinitJumpServer jumpServer, WinitInfo winitInfo, boolean needFailConfirm) throws Exception {
        return getTaskNode(typeEnum, step, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm, false);
    }

    private TaskNode getTaskNode(PackageTypeEnum typeEnum, DeployStepEnum step, String taskId, Server server, boolean isUserJumpServer
            , WinitJumpServer jumpServer, WinitInfo winitInfo, boolean needFailConfirm, boolean isCleanRedis) throws Exception {
        TaskNode taskNode = null;
        switch (typeEnum) {
            case MAVEN_WAR:
                taskNode = getTomcatTaskNode(step, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm, isCleanRedis);
                break;
            case PHP:
                taskNode = getPhpTaskNode(step, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm);
                break;
            case ANT_ANDROID:
                taskNode = getAndroidTaskNode(step, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm);
                break;
            case SPRING_BOOT_JAR:
                taskNode = getSpringBootTaskNode(step, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm);
                break;
            default:
                logger.error("生成发布用TaskNode,参数错误.step=" + step.getStep() + ",typeEnum=" + typeEnum.getDesc());
                throw new Exception("生成发布用TaskNode,参数错误.step=" + step.getStep() + ",typeEnum=" + typeEnum.getDesc());
        }
        return taskNode;
    }

    private TaskNode getTomcatTaskNode(DeployStepEnum step, String taskId, Server server, boolean isUserJumpServer
            , WinitJumpServer jumpServer, WinitInfo winitInfo, boolean needFailConfirm) throws Exception {
        return getTomcatTaskNode(step, taskId, server, isUserJumpServer, jumpServer, winitInfo, needFailConfirm, false);
    }

    private TaskNode getTomcatTaskNode(DeployStepEnum step, String taskId, Server server, boolean isUserJumpServer
            , WinitJumpServer jumpServer, WinitInfo winitInfo, boolean needFailConfirm, boolean isCleanRedis) throws Exception {
        TaskNode taskNode = null;
        WinitTomcatServer tomcatServer = (WinitTomcatServer) server;
        WinitTomcatInfo tomcatInfo = (WinitTomcatInfo) winitInfo;
        Task task = null;

        switch (step) {
            case PREPARE:
                if (isUserJumpServer) {
                    task = new DeployPrepareTask(taskId, 600, tomcatServer, jumpServer, tomcatInfo);
                } else {
                    task = new DeployPrepareTask(taskId, 600, tomcatServer, tomcatInfo);
                }
                break;
            case STOP:
                task = new DeployStopServerTask(taskId, 300, tomcatServer);
                break;
            case BAK:
                task = new DeployBakTask(taskId, 300, tomcatServer);
                break;
            case INSTALL:
                task = new DeployInstallTask(taskId, 300, tomcatServer);
                break;
            case START:
                task = new DeployStartServerTask(taskId, 300, isCleanRedis, tomcatServer);
                break;
            case VERIFY:
                task = new DeployVerifyTask(taskId, 300, tomcatServer);
                break;
            case ROLLBACK:
                task = new DeployRollBackTask(taskId, 300, tomcatServer);
                break;
            default:
                logger.error("生成发布用TaskNode,参数错误.step=" + step.getStep() + ",typeEnum=tomcat");
                throw new Exception("生成发布用TaskNode,参数错误.step=" + step.getStep() + ",typeEnum=tomcat");
        }
        taskNode = new TaskNode(task, needFailConfirm, step.getIndex());
        return taskNode;
    }

    private TaskNode getPhpTaskNode(DeployStepEnum step, String taskId, Server server, boolean isUserJumpServer
            , WinitJumpServer jumpServer, WinitInfo winitInfo, boolean needFailConfirm) throws Exception {
        TaskNode taskNode = null;
        WinitPhpServer phpServer = (WinitPhpServer) server;
        WinitPhpInfo phpInfo = (WinitPhpInfo) winitInfo;
        Task task = null;
        switch (step) {
            case PREPARE:
                if (isUserJumpServer) {
                    task = new PhpPrepareTask(taskId, 600, phpInfo, phpServer, jumpServer);
                } else {
                    task = new PhpPrepareTask(taskId, 600, phpInfo, phpServer);
                }
                break;
            case STOP:
                task = new PhpStopServerTask(taskId, 300, phpServer);
                break;
            case BAK:
                task = new PhpBakTask(taskId, 300, phpServer);
                break;
            case INSTALL:
                task = new PhpInstallTask(taskId, 300, phpServer);
                break;
            case START:
                task = new PhpStartServerTask(taskId, 300, phpServer);
                break;
            case ROLLBACK:
                task = new PhpRollBackTask(taskId, 300, phpServer);
                break;
            default:
                logger.error("生成发布用TaskNode,参数错误.step=" + step.getStep() + ",typeEnum=php");
                throw new Exception("生成发布用TaskNode,参数错误.step=" + step.getStep() + ",typeEnum=php");
        }
        taskNode = new TaskNode(task, needFailConfirm, step.getIndex());
        return taskNode;
    }

    private TaskNode getAndroidTaskNode(DeployStepEnum step, String taskId, Server server, boolean isUserJumpServer
            , WinitJumpServer jumpServer, WinitInfo winitInfo, boolean needFailConfirm) throws Exception {
        TaskNode taskNode = null;
        WinitAndroidServer androidServer = (WinitAndroidServer) server;
        WinitAndroidInfo androidInfo = (WinitAndroidInfo) winitInfo;
        Task task = null;
        switch (step) {
            case PREPARE:
                if (isUserJumpServer) {
                    task = new AndroidPrepareTask(taskId, 600, androidInfo, androidServer, jumpServer);
                } else {
                    task = new AndroidPrepareTask(taskId, 600, androidInfo, androidServer);
                }
                break;
            case BAK:
                task = new AndroidBakTask(taskId, 300, androidServer);
                break;
            case INSTALL:
                task = new AndroidInstallTask(taskId, 300, androidServer);
                break;
            case ROLLBACK:
                task = new AndroidRollBackTask(taskId, 300, androidServer);
                break;
            default:
                logger.error("生成发布用TaskNode,参数错误.step=" + step.getStep() + ",typeEnum=android");
                throw new Exception("生成发布用TaskNode,参数错误.step=" + step.getStep() + ",typeEnum=android");
        }
        taskNode = new TaskNode(task, needFailConfirm, step.getIndex());
        return taskNode;
    }

    private TaskNode getSpringBootTaskNode(DeployStepEnum step, String taskId, Server server, boolean isUserJumpServer
            , WinitJumpServer jumpServer, WinitInfo winitInfo, boolean needFailConfirm) throws Exception {
        TaskNode taskNode = null;

        WinitSpringBootServer springBootServer = (WinitSpringBootServer) server;
        WinitSpringBootInfo springBootInfo = (WinitSpringBootInfo) winitInfo;
        Task task = null;
        switch (step) {
            case PREPARE:
                if (isUserJumpServer) {
                    task = new SpringBootPrepareTask(taskId, 600, springBootServer, jumpServer, springBootInfo);
                } else {
                    task = new SpringBootPrepareTask(taskId, 600, springBootServer, springBootInfo);
                }
                break;
            case STOP:
                task = new SpringBootStopTask(taskId, 300, springBootServer);
                break;
            case BAK:
                task = new SpringBootBakTask(taskId, 300, springBootServer);
                break;
            case INSTALL:
                task = new SpringBootInstallTask(taskId, 300, springBootServer);
                break;
            case START:
                task = new SpringBootStartTask(taskId, 300, springBootServer);
                break;
            case ROLLBACK:
                task = new SpringBootRollBackTask(taskId, 300, springBootServer);
                break;
            default:
                logger.error("生成发布用TaskNode,参数错误.step=" + step.getStep() + ",typeEnum=springboot");
                throw new Exception("生成发布用TaskNode,参数错误.step=" + step.getStep() + ",typeEnum=springboot");
        }
        taskNode = new TaskNode(task, needFailConfirm, step.getIndex());
        return taskNode;
    }

    private ChainBaseTask.TaskHandler createDefaultTaskHandler() {
        ChainBaseTask.TaskHandler handler = new ChainBaseTask.TaskHandler() {

            @Override
            public void handleTaskNodeStatus(String taskId, List<String> taskNodeStatus) {
                System.out.println(DateUtil.getCurDateStr(DateUtil.FORMAT_SS) + "handleTaskNodeStatus:");
                for (String s : taskNodeStatus)
                    System.out.println(DateUtil.getCurDateStr(DateUtil.FORMAT_SS) + "执行状态=======" + s);
            }

            @Override
            public void handleChainTaskStatus(String taskId, String taskStatus) {
                System.out.println(DateUtil.getCurDateStr(DateUtil.FORMAT_SS) + "handleChainTaskStatus:" + taskStatus);
            }

            @Override
            public void handleChainTaskMessage(String taskId, String message) {
                System.out.println(DateUtil.getCurDateStr(DateUtil.FORMAT_SS) + "handleChainTaskMessage:" + message);
            }
        };
        return handler;
    }
}